package base;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.Map.Entry;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import base.InvertVertexBuilder.InvertVertex;
import collect.Functions;

import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.Sets;

public class Inverter {

	private final ImmutableDynamic on;
	private final Support fixed;
	private double designability;
	private double logD;
	private final static ExecutorService majordomo = Executors.newCachedThreadPool();
	
	private final int pow2;
	private final int pow3;
	private final long[] enumCore;
	public Inverter(ImmutableDynamic on) {
		this.on = on;
		Support.FutureBuilder fromFutures = Support.futureBuilder(on.vertices().size());
		for (Integer vertex : on.vertices()) 
			fromFutures.put(vertex, majordomo.submit(new InvertVertexBuilder(on, vertex, Support.NonSelfInhibiting.get())));
		fixed = fromFutures.build();
		designability = 1d;
		logD = 0d;
		int temppow2 = 0;
		int temppow3 = 0;
		enumCore = new long[on.vertices().size()];
		for (Entry<Integer,InvertVertex> iv : fixed) {
			if (!iv.getValue().isFeasible()) {
				designability = 0;
				logD = -1;
				temppow2=0;
				temppow3=0;
				break;
			}
			designability *= iv.getValue().designability();
			logD += iv.getValue().logD();
			temppow2+=iv.getValue().pow2();
			temppow3+=iv.getValue().pow3();
			enumCore[iv.getKey()] = iv.getValue().enumCount()!=0 ? iv.getValue().enumCount() : 1;
		}
		pow2 = temppow2;
		pow3 = temppow3;
	}
	
	
	
	public int activity() {
		return on.activity();
	}
	
	public double logD() {
		return logD;
	}
	
	public double designability() {
		return designability;
	}
	
	private int minimalSize = -1;
	public int minimalSize() {
		if (minimalSize < 0) {
			minimalSize = minimumSize(this);
		}
		return minimalSize;
	}

	private ImmutableBiMap<List<VertexState>,Integer> index;

	static class Tri {
		final long enumcount;
		final int pow2;
		final int pow3;
		Tri(long enumcount, int pow2, int pow3) {
			this.enumcount = enumcount;
			this.pow2 = pow2;
			this.pow3 = pow3;
		}
		
		long getE() { return enumcount; }
		int pow2() { return pow2; }
		int pow3() { return pow3; }
	}

	
	public double[][] heatMap() {
		if (heatMap!=null) return heatMap;
		heatMap = new double[1 << on.vertices().size()][1 << on.vertices().size()];
		deltaG = new int[heatMap.length][heatMap.length];
		
		for (int i=0; i< heatMap.length; i++)
			for (int j=0; j<heatMap[i].length; j++) {
				heatMap[i][j]=0d;
				deltaG[i][j]=0;
			}
		
		int outOf = 0;
		
		{
			int i=0;
			ImmutableBiMap.Builder<List<VertexState>,Integer> builder = ImmutableBiMap.builder();
			for (SupportState s : on.fixedSources()) builder.put(s.asList(),i++);
			for (SupportState s : on.unfixedSources()) {
				builder.put(s.asList(), i++);
				outOf++;
			}
			index = builder.build();
		}
				
		for (SupportState s : on.fixedSources()) {
			heatMap[index.get(s.asList())][index.get(on.get(s).asList())] = 1d;
		}

		
		Map<SupportState,List<Map<VertexState,Tri>>> enums = Maps.newHashMapWithExpectedSize(outOf);
		Map<SupportState,List<Map<VertexState,Integer>>> fixes = Maps.newHashMapWithExpectedSize(outOf);
		int count = 0;
		int currentSize = fixed.fixedSize();

//		int limit = 20;
		for (SupportState s : on.unfixedSources()) {
//			if (count > limit) break;
			System.out.println("Crunching "+s+" : "+ (++count) + " of "+outOf);
						
			List<Map<VertexState,Tri>> enumAdd = null;
			List<Map<VertexState,Integer>> fixedAdd = null;
			
			{
				List<Map<VertexState,InvertVertex>> crunched;
				List<Map<VertexState,Future<Long>>> futureL;
				
//				List<InvertVertex> crunched;
//				List<Future<Long>> futureL;

				List<Map<VertexState,Future<InvertVertex>>> crunch = Lists.newArrayListWithCapacity(on.vertices().size());
//				List<Future<InvertVertex>> crunch = Lists.newArrayListWithCapacity(on.vertices().size());

				for ( Integer vertex : on.vertices() ) {
					Map<VertexState,Future<InvertVertex>> put = Maps.newEnumMap(VertexState.class);
					//TODO just put one in - other will be Dinitial - Dresult
					for (VertexState vs : VertexState.both) {
						put.put(vs, majordomo.submit(fixed.fixedInto(vertex).apply(s, vs)));
					}
					crunch.add(put);
//					crunch.add(majordomo.submit(fixed.fixedInto(vertex).apply(s, VertexState.ON)));
				}
			
				ImmutableList.Builder<Map<VertexState,InvertVertex>> bIV = ImmutableList.builder();
				ImmutableList.Builder<Map<VertexState,Future<Long>>> bL = ImmutableList.builder();
				ImmutableList.Builder<Map<VertexState,Integer>> bF = ImmutableList.builder();
//				ImmutableList.Builder<InvertVertex> bIV = ImmutableList.builder();
//				ImmutableList.Builder<Future<Long>> bL = ImmutableList.builder();

				for (Map<VertexState, Future<InvertVertex>> m : crunch) {
					Map<VertexState,Future<Long>> mbL = Maps.newEnumMap(VertexState.class);
					Map<VertexState,InvertVertex> mbIV = Maps.newEnumMap(VertexState.class);
					Map<VertexState,Integer> mbF = Maps.newEnumMap(VertexState.class);

					for (Entry<VertexState,InvertVertex> e : Maps.filterValues(Maps.transformValues(m, Functions.<InvertVertex>getter()), feasible).entrySet()) {
						InvertVertex iv = e.getValue();
						mbL.put(e.getKey(),majordomo.submit(iv));
						mbIV.put(e.getKey(), iv);
						mbF.put(e.getKey(), iv.g().size()+iv.r().size()+iv.not().size());
					}
					bIV.add(mbIV);
					bL.add(mbL);
					bF.add(mbF);
				}
				
//				for (InvertVertex iv : Iterables.transform(crunch, Functions.<InvertVertex>getter())) {
//					bIV.add(iv);
//					bL.add(majordomo.submit(iv));
//				}

				
				crunched = bIV.build();
				futureL = bL.build();
				fixedAdd = bF.build();
				
				try {
					ImmutableList.Builder<Map<VertexState,Tri>> b = ImmutableList.builder();
					for (int i=0; i<crunched.size(); i++) {
						Map<VertexState,Tri> put = Maps.newEnumMap(VertexState.class);
						for (VertexState v : crunched.get(i).keySet()) 
							put.put(v,new Tri(futureL.get(i).get(v).get(),crunched.get(i).get(v).pow2(),crunched.get(i).get(v).pow3()));
						b.add(put);
					}
					enumAdd = b.build();
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			
			}
			fixes.put(s, fixedAdd);
			enums.put(s, enumAdd);
		}
			
		for (SupportState from : enums.keySet()) {
			List<Map<VertexState,Tri>> crunched = enums.get(from);
			List<Map<VertexState,Integer>> fixedSizes = fixes.get(from);
					
			double[] row = heatMap[index.get(from.asList())];
			int[] fixedRow = deltaG[index.get(from.asList())];
			for (List<VertexState> support : Sets.cartesianProduct(Lists.transform(crunched, asSupportState))){
				int delta = -currentSize;
				double put = 1;
				int net2 = -pow2;
				int net3 = -pow3;
				for (Integer vertex : on.vertices()) {
					double div = enumCore[vertex];
					Tri perturbed = crunched.get(vertex).get(support.get(vertex));
					double num = perturbed.getE() != 0 ? perturbed.getE() : 1;
					net2 += perturbed.pow2();
					net3 += perturbed.pow3(); 
					put *= num/div;
					delta += fixedSizes.get(vertex).get(support.get(vertex));
				}
				
				put = Math.scalb(put, net2);
				put *= Math.pow(3, net3);
				
				if (put > 1) System.out.println(from+" => "+support);
				
				row[index.get(support)] = put;
				fixedRow[index.get(support)] = delta;
			}
			double sum = 0;
			for (double prob : row) sum+=prob;
			if (Math.abs(sum-1d) > 0.001) {
				System.out.println(from+" "+sum);
				for (int i=0; i<row.length; i++) {
					if (row[i]!=0) System.out.println("\t"+Joiner.on(' ').join(index.inverse().get(i)).toString()+" "+Double.toString(row[i]));
				}
			}
		}
		
		return heatMap;
	}
				
	private static final Predicate<InvertVertex> feasible = new Predicate<InvertVertex>() {
		@Override public boolean apply(InvertVertex input) { return input.isFeasible(); }		
	};
		
	@SuppressWarnings("unchecked")
	private static final Function<Map,Set<VertexState>> asSupportState =
		new Function<Map,Set<VertexState>>() {
			@Override public Set<VertexState> apply(Map from) {
				return from.keySet();
			}
	};
	
	private double[][] heatMap;
	private int[][] deltaG;
	private int[][] deltaR;
	
	public static double[][] deepClone(double[][] source) {
		double[][] result = new double[source.length][source.length];
		for (int i=0; i<source.length ; i++) result[i] = source[i].clone();
		return result;
	}
	
	public static int minimumSize(Inverter i) {
		int minimumSize = 0;
		for (Entry<Integer,InvertVertex> v : i.fixed) minimumSize += InverterUtils.minimumSize(v.getValue());
		return minimumSize;
	}

	public static int minimumSizeNonAuto(Inverter i) {
		int minimumSize = 0;
		for (Entry<Integer,InvertVertex> v : i.fixed) minimumSize += InverterUtils.minimumSizeNonAuto(v.getValue());
		return minimumSize;
	}

	public static int estimateMinimum(Inverter i) {
		int minimumSize = 0;
		for (Entry<Integer,InvertVertex> v : i.fixed) minimumSize += InverterUtils.estimateMinimumSize(v.getValue());
		return minimumSize;		
	}

	public void tryFrom(SupportState from) {
		
		List<Map<VertexState,InvertVertex>> crunched;

		List<Map<VertexState,Future<InvertVertex>>> crunch = Lists.newArrayListWithCapacity(on.vertices().size());
		for ( Integer vertex : on.vertices() ) {
			Map<VertexState,Future<InvertVertex>> put = Maps.newEnumMap(VertexState.class);
			for (VertexState vs : VertexState.both) {
				put.put(vs, majordomo.submit(fixed.fixedInto(vertex).apply(from, vs)));
			}
			crunch.add(put);
		}
		
		ImmutableList.Builder<Map<VertexState,InvertVertex>> bIV = ImmutableList.builder();
		for (Map<VertexState, Future<InvertVertex>> m : crunch) {
			Map<VertexState,Future<Long>> mbL = Maps.newEnumMap(VertexState.class);
			Map<VertexState,InvertVertex> mbIV = Maps.newEnumMap(VertexState.class);

			for (Entry<VertexState,InvertVertex> e : Maps.filterValues(Maps.transformValues(m, Functions.<InvertVertex>getter()), feasible).entrySet()) {
				mbL.put(e.getKey(),majordomo.submit(e.getValue()));
				mbIV.put(e.getKey(), e.getValue());
			}
			bIV.add(mbIV);
		}
		crunched = bIV.build();
		
		SetMultimap<VertexState,Integer> pool = HashMultimap.create();
		for (int i=0; i< crunched.size() ; i++) {
			for (VertexState v : crunched.get(i).keySet())
				pool.put(v, i);
		}
		
		for (List<VertexState> support : Sets.cartesianProduct(Lists.transform(crunched, asSupportState))){
			ImmutableDynamic.Builder b = ImmutableDynamic.builder(on);
			b.put(from,new SupportState(support));
			Inverter other = new Inverter(b.build());
			for (Entry<Integer,InvertVertex> e : other.fixed) if (pool.values().contains(e.getKey())) {
				InvertVertex iv = e.getValue();
				InvertVertex crun = crunched.get(e.getKey()).get(support.get(e.getKey()));
				if (!iv.fixedComponent().equals(crun.fixedComponent()) || !iv.gTerms.equals(crun.gTerms) || !iv.justR.equals(crun.justR) ||
						!iv.rTerms.equals(crun.rTerms)	) {
					System.out.println("Vertex : "+e.getKey()+" turned to "+support.get(e.getKey()));
					if (!iv.fixedComponent().equals(crun.fixedComponent())) for (Edge edge : iv.fixedComponent().keySet()) {
						if (!iv.fixedComponent().get(edge).equals(crun.fixedComponent().get(edge))) System.out.println("f diff for "+edge+" : "+Sets.difference(iv.fixedComponent().get(edge), crun.fixedComponent().get(edge))+" vs "+Sets.difference(crun.fixedComponent().get(edge), iv.fixedComponent().get(edge)));
					}
					if (!iv.gTerms.equals(crun.gTerms))
						System.out.println("g diff; iv-crun, crun-iv :"+Sets.difference(iv.gTerms,crun.gTerms)+" , "+Sets.difference(crun.gTerms,iv.gTerms));
					if (!iv.rTerms.equals(crun.rTerms))
						System.out.println("rTerm :"+Maps.difference(iv.rTerms.asMap(), crun.rTerms.asMap()));
					if (!iv.justR.equals(crun.justR))
						System.out.println("justR diff; iv-crun, crun-iv :"+Sets.difference(iv.justR,crun.justR)+" , "+Sets.difference(crun.justR,iv.justR));
				}
				
				pool.remove(support.get(e.getKey()), e.getKey());
				
				if (pool.isEmpty()) break;
			}
		}
		
		//on.append();
	}
	
	public static void main(String...args) {
		ImmutableDynamic.Builder b = ImmutableDynamic.builder(11);

		b.putNext(new SupportState(true ,false,false,false,true ,false,false,false,true ,false,false));
		b.putNext(new SupportState(false,true ,true ,false,true ,false,false,false,true ,false,false));
		b.putNext(new SupportState(false,true ,true ,true ,true ,false,false,false,true ,false,false));
		b.putNext(new SupportState(false,true ,true ,true ,false,false,false,false,false,false,false));
		b.putNext(new SupportState(false,true ,true ,true ,false,false,false,true ,false,false,false));
		b.putNext(new SupportState(false,true ,true ,true ,false,false,false,true ,false,true ,true ));
		b.putNext(new SupportState(false,false,false,true ,false,false,true ,true ,false,true ,true ));
		b.putNext(new SupportState(false,false,false,false,false,false,true ,false,false,false,true ));
		b.putNext(new SupportState(false,false,false,false,true ,true ,true ,false,true, false,false));
		b.putNext(new SupportState(false,false,false,false,true ,true ,false,false,true, false,false));
		b.putNext(new SupportState(false,false,false,false,true ,false,false,false,true, false,false));
		b.putNext(new SupportState(false,false,false,false,true ,false,false,false,true, false,false));

		
//		b.putNext(new SupportState(false,false,false,true ,false,true ,false,false,false,false,false));
//		b.putNext(new SupportState(false,false,true ,true ,false,false,false,false,false,false,false));
//		b.putNext(new SupportState(false,true ,false,false,false,false,true ,true ,false,false,false));
//		b.putNext(new SupportState(false,false,false,false,false,false,false,true ,false,false,false));
//		b.putNext(new SupportState(false,false,false,true ,false,false,false,false,false,false,false));
//		b.putNext(new SupportState(false,false,false,true ,false,false,true ,true ,false,true ,false));
//		b.putNext(new SupportState(false,false,false,false,true ,false,false,false,false,true ,false));
//		b.putNext(new SupportState(true, true ,true ,false,false,false,false,false,true ,false,false));
//		b.putNext(new SupportState(true, false,false,false,false,false,true ,true ,false,false,false));
//		b.putNext(new SupportState(false,false,false,true ,false,false,true ,false,false,false,true ));
//		b.putNext(new SupportState(false,false,true ,false,true ,false,false,false,false,false,true ));
//		b.putNext(new SupportState(false,false,true ,false,true ,false,false,false,false,false,true ));
		
		Inverter test= new Inverter(b.build());

		for (Entry<Integer,InvertVertex> e : test.fixed) {
			InvertVertex iv = e.getValue();
			System.out.println("Vertex : "+e.getKey());
			System.out.println("f : "+iv.fixedComponent());
			System.out.println("g : "+iv.gTerms);
			System.out.println("r/g : "+iv.rTerms);
			System.out.println("r : "+iv.justR);
			System.out.println("d :"+iv.designability());
		}
		

		
		System.out.println("total 2: "+test.pow2);
		System.out.println("total 3: "+test.pow3);
		System.out.println("total enum: "+Arrays.toString(test.enumCore));
		double d = 1;
		for (long e : test.enumCore) d*=e;
		d = Math.scalb(d, test.pow2);
		d *= Math.pow(3, test.pow3);
		System.out.println("total d: "+d);
//		
		System.exit(0);
		
		System.out.println("\n ---- \n");
//
//	//	 ,=> [OFF OFF OFF OFF OFF OFF OFF OFF OFF OFF OFF]
//		
//		boolean[] from = {false, false, true, true, false, false, false, true, false, true, false};
//		boolean[] to = {false, false, false, false, false, false, false, false, false, false, false};
//
//		test.tryFrom(new SupportState(from));
//		
//		System.exit(0);
//		
//		double put = 1;
//		int net2 = -test.pow2;
//		int net3 = -test.pow3;
//		
//		b.put(	new SupportState(from),
//				new SupportState(to));
//		Inverter test2 = new Inverter(b.build());
//		System.out.println("\n ---- \n");
//		for (Entry<Integer,InvertVertex> e : test.fixed) {
//			InvertVertex test2iv = e.getValue()
//				.apply(	new SupportState(from),
//						new SupportState(to));
////			InvertVertex test2iv = test2.fixed.fixedInto(e.getKey());
//			System.out.println("Vertex : "+e.getKey());
//			System.out.println("f : "+test.fixed.fixedInto(e.getKey()).fixedComponent()+" vs "+test2iv.fixedComponent());
//			System.out.println("g : "+test.fixed.fixedInto(e.getKey()).gTerms+" vs "+test2iv.gTerms);
//			System.out.println("r/g : "+test.fixed.fixedInto(e.getKey()).rTerms+" vs "+test2iv.rTerms);
//			System.out.println("r : "+test.fixed.fixedInto(e.getKey()).justR+" vs "+test2iv.justR);
//			System.out.println("pow2 : "+test.fixed.fixedInto(e.getKey()).pow2()+" vs "+test2iv.pow2());
//			System.out.println("pow3 : "+test.fixed.fixedInto(e.getKey()).pow3()+" vs "+test2iv.pow3());
//			System.out.println("enum : "+test.fixed.fixedInto(e.getKey()).enumCount()+" vs "+test2iv.enumCount());
//
//				double div = test.enumCore[e.getKey()];
//				double num = test2iv.enumCount() != 0 ? test2iv.enumCount() : 1;
//				net2 += test2iv.pow2();
//				net3 += test2iv.pow3(); 
//				put *= num/div;
//			
//		}
//		
//		put = Math.scalb(put, net2);
//		put *= Math.pow(3, net3);
//		System.out.println(put);
//		
//		System.out.println("total 2: "+test2.pow2);
//		System.out.println("total 3: "+test2.pow3);
//		System.out.println("total enum: "+Arrays.toString(test2.enumCore));
//		d = 1;
//		for (long e : test2.enumCore) d*=e;
//		d = Math.scalb(d, test2.pow2);
//		d *= Math.pow(3, test2.pow3);
//		System.out.println("total d: "+d);
//
//		
//		System.exit(0);
				
		try {
			NumberFormat formatter = new DecimalFormat("0.000000");
			
			BufferedWriter heatmapFile = new BufferedWriter(new FileWriter("heatmap.out"));
			BufferedWriter deltaFixedFile = new BufferedWriter(new FileWriter("deltaFixed.out"));

			double[][] heatMap = test.heatMap();
			int[][] deltaFixed = test.deltaG;
			heatmapFile.write("index");
			deltaFixedFile.write("index");
			for (int i=0;i<heatMap.length; i++) {
				heatmapFile.write(" "+i);
				deltaFixedFile.write(" "+i);
			}
			heatmapFile.newLine();
			deltaFixedFile.newLine();
			int index=0;
			for (int j=0; j<heatMap.length; j++) {
				double[] row = heatMap[j];
				int[] deltaRow = deltaFixed[j];
				heatmapFile.write(Integer.toString(index));
				deltaFixedFile.write(Integer.toString(index));
				index++;
				
				for (int i=0;i<row.length;i++) {
					if (row[i]==1d) {
						heatmapFile.write(" 1");						
					} else if (row[i]==0d || row[i] < 0.00000005 ) { 
						heatmapFile.write(" 0");
					} else heatmapFile.write(" "+formatter.format(row[i]));
				}
				heatmapFile.newLine();
				
				for (int i=0;i<deltaRow.length;i++) {
					deltaFixedFile.write(" "+deltaRow[i]);
				}
				deltaFixedFile.newLine();
				
			}
			heatmapFile.close();
			deltaFixedFile.close();
			
			BufferedWriter indexfile = new BufferedWriter(new FileWriter("index.out"));
			indexfile.write("index");
			
			for ( int i=0; i < test.on.vertices().size() ; i++)
				indexfile.write(" "+i);
			indexfile.newLine();
			Joiner joiner = Joiner.on(" ");
			for (Entry<List<VertexState>,Integer> e : test.index.entrySet()) {
				indexfile.write(e.getValue()+" "+joiner.join(Lists.transform(e.getKey(), new Function<VertexState,Integer>(){
					@Override public Integer apply(VertexState from) {
						return from==VertexState.ON ? 1 : 0;
					}					
				})).toString());
				indexfile.newLine();
			}
			indexfile.close();
			
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}

		majordomo.shutdown();
		System.exit(0);

		
		//System.out.println("Input successive states of "+args[0]+" 1s and 0s.");
		BufferedReader input = null;
		BufferedWriter output1 = null;
		BufferedWriter output2 = null;
		int[] size = {15};
		String[] append = {"70","71"}; //,"02","03","04","05","06","07","08","09"};
		for (int s : size) {
			for (String app : append) {
				System.out.println(s+" "+append);
				try {
					input = new BufferedReader(new FileReader(s+"x"+(s+1)+"-"+app));
					output1 = new BufferedWriter(new FileWriter(s+"x"+(s+1)+"-"+app+"d.out"));
					output2 = new BufferedWriter(new FileWriter(s+"x"+(s+1)+"-"+app+"nonzeros.out"));
				} catch (FileNotFoundException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				} finally {
					if (input==null || output1==null || output2 == null) System.exit(0);
				}
				
				Scanner linescanner = new Scanner(input);
				Scanner interpreter;
				ImmutableDynamic.Builder builder = ImmutableDynamic.builder(s);
				while (!linescanner.hasNextInt()) linescanner.nextLine();
				int index;
				boolean[] line = new boolean[s];
				
				int count = 0;
				
				while (linescanner.hasNextLine()) {
					interpreter = new Scanner(linescanner.nextLine());
					index = 0;
					if (interpreter.hasNextInt()) {
						while (interpreter.hasNextInt()) line[index++] = interpreter.nextInt() == 0 ? false : true;
						builder.putNext(new SupportState(line));
					} else {
						while (!linescanner.hasNextInt() && linescanner.hasNextLine()) linescanner.nextLine();
						count++;
						Inverter invert = new Inverter(builder.build());
						int delta = Inverter.estimateMinimum(invert)-Inverter.minimumSize(invert);
						try {
							output1.write(invert.logD() + " " + invert.activity() + " "+delta+" "+Inverter.minimumSizeNonAuto(invert));
							output1.newLine();
							if (delta>2) {
								output2.write(invert.on.toString());
								output2.newLine();
								for (Entry<Integer,InvertVertex> e : invert.fixed) if(InverterUtils.estimateMinimumSize(e.getValue())-InverterUtils.minimumSize(e.getValue())!=0) {
									output2.write(e.getKey()+" vertex : fixed "+e.getValue().fixedComponent);
									output2.newLine();
									output2.write(e.getKey()+" vertex : gTerms "+e.getValue().gTerms);
									output2.newLine();
									output2.write(e.getKey()+" vertex : justR "+e.getValue().justR);
									output2.newLine();
									output2.write(e.getKey()+" vertex : rTerms "+e.getValue().rTerms);
									output2.newLine();
								}
								output2.newLine();
							}
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						if (count % 100 == 0) {
							try {
								output1.flush();
								output2.flush();
							} catch (IOException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
							System.out.println(count);
						}
						builder = ImmutableDynamic.builder(s);
					}
				}
				
				try {
					output1.close();
					output2.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

				
			}
		}
	}
	
}
